001 /* 002 * Copyright 2004 Niclas Hedhman 003 * Copyright 2004-2006 Stephen J. McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. 015 * 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020 package net.dpml.transit.artifact; 021 022 import java.io.InputStream; 023 import java.io.IOException; 024 import java.io.OutputStream; 025 import java.io.File; 026 import java.net.UnknownServiceException; 027 import java.net.URI; 028 import java.net.URL; 029 import java.net.URLConnection; 030 import java.net.URISyntaxException; 031 032 import net.dpml.transit.Artifact; 033 import net.dpml.transit.Transit; 034 import net.dpml.transit.SecuredTransitContext; 035 import net.dpml.transit.CacheHandler; 036 037 import net.dpml.lang.Part; 038 039 import net.dpml.util.MimeTypeHandler; 040 041 /** 042 * The connection handler for URLs based on the "artifact" protocol family. 043 * @author <a href="http://www.dpml.net">The Digital Product Meta Library</a> 044 * @version 1.0.0 045 */ 046 public class ArtifactURLConnection extends URLConnection 047 { 048 // ------------------------------------------------------------------------ 049 // state 050 // ------------------------------------------------------------------------ 051 052 /** 053 * Transit context. 054 */ 055 private final SecuredTransitContext m_context; 056 057 /** 058 * Artifact. 059 */ 060 private final Artifact m_artifact; 061 062 /** 063 * Reference fragment. 064 */ 065 private final String m_reference; 066 067 /** 068 * The connected state. 069 */ 070 private boolean m_connected; 071 072 // ------------------------------------------------------------------------ 073 // constructor 074 // ------------------------------------------------------------------------ 075 076 /** 077 * Creation of a new handler. 078 * @param url the url to establish a connection with 079 * @param context the transit context 080 * @exception NullPointerException if the url argument is null 081 * @exception IOException if the url argument is not a valid, 082 * i.e. the path must contain a group and an artifactId 083 * separated by a slash. 084 */ 085 ArtifactURLConnection( URL url, SecuredTransitContext context ) 086 throws NullPointerException, IOException 087 { 088 super( url ); 089 090 Transit.getInstance(); // make sure Transit is initialized 091 092 m_context = context; 093 m_reference = getReference( url ); 094 095 String spec = getRealSpec( url, m_reference ); 096 try 097 { 098 m_artifact = Artifact.createArtifact( spec ); 099 } 100 catch( URISyntaxException e ) 101 { 102 throw new IOException( e.toString() ); 103 } 104 } 105 106 // ------------------------------------------------------------------------ 107 // URLConnection 108 // ------------------------------------------------------------------------ 109 110 /** 111 * Establish a connection. The implementation will attempt to 112 * resolve the resource relative to the cache and associated hosts. 113 * 114 * @exception IOException is an error occurs while attempting to establish 115 * the connection. 116 */ 117 public void connect() 118 throws IOException 119 { 120 m_connected = true; 121 } 122 123 /** 124 * Return an input stream to the resource. 125 * @return the input stream 126 * @exception IOException is an error occurs 127 */ 128 public InputStream getInputStream() 129 throws IOException 130 { 131 connect(); 132 CacheHandler cache = m_context.getCacheHandler(); 133 if( null != m_reference ) 134 { 135 return cache.getResource( m_artifact, m_reference ); 136 } 137 else 138 { 139 return cache.getResource( m_artifact ); 140 } 141 } 142 143 /** 144 * Return an output stream to the resource. 145 * @return the output stream 146 * @exception IOException if any I/O problems occur. 147 */ 148 public OutputStream getOutputStream() 149 throws IOException 150 { 151 CacheHandler cache = m_context.getCacheHandler(); 152 return cache.createOutputStream( m_artifact ); 153 } 154 155 /** 156 * Reutrn the mimetype of the content. 157 * @return the content mimetype 158 */ 159 public String getContentType() 160 { 161 String type = m_artifact.getType(); 162 return MimeTypeHandler.getMimeType( type ); 163 } 164 165 /** 166 * Return the content for this artifact. 167 * @return the content object (possibly null) 168 * @exception IOException is an error occurs 169 */ 170 public Object getContent() 171 throws IOException 172 { 173 Object content = getContent( new Class[0] ); 174 if( content != null ) 175 { 176 return content; 177 } 178 else 179 { 180 return super.getContent(); 181 } 182 } 183 184 /** 185 * Return the content for this artifact. 186 * @param classes a sequence of classes against which the 187 * implementation will attempt to establish a known match 188 * @return the content object (possibly null) 189 * @exception IOException is an error occurs 190 */ 191 public Object getContent( Class[] classes ) 192 throws IOException 193 { 194 String type = m_artifact.getType(); 195 196 // 197 // if the type is a plugin then handle this directly 198 // 199 200 if( "part".equals( type ) ) 201 { 202 URI uri = m_artifact.toURI(); 203 Part part = Part.load( uri ); 204 return part.getContent( classes ); 205 } 206 207 // 208 // otherwise fallback on the default jvm content handling 209 // 210 211 try 212 { 213 Object content = super.getContent( classes ); 214 if( content != null ) 215 { 216 return content; 217 } 218 } 219 catch( UnknownServiceException use ) 220 { 221 boolean ignoreThis = true; 222 } 223 224 // 225 // attempt to resolve this locally as we may be dealing 226 // with Magic references to the artifact File 227 // 228 229 for( int i=0; i < classes.length; i++ ) 230 { 231 Class c = classes[i]; 232 if( c.equals( File.class ) ) 233 { 234 return m_context.getCacheHandler().getLocalFile( m_artifact ); 235 } 236 } 237 return null; 238 } 239 240 // ------------------------------------------------------------------------ 241 // implementation 242 // ------------------------------------------------------------------------ 243 244 /** 245 * Return a fragment referencing content within the resource referenced by 246 * the artifact. 247 * @param url the url 248 * @return the fragment or null if this is not a referential url 249 */ 250 private String getReference( URL url ) 251 { 252 String path = url.getPath(); 253 int i = path.indexOf( '!' ); 254 if( i < 0 ) 255 { 256 return null; 257 } 258 else 259 { 260 return path.substring( i ); 261 } 262 } 263 264 /** 265 * Return the real specification of the supplied url. 266 * @param url the url to evaluate 267 * @param ref a reference fragment 268 * @return the artifact url spec withough the ref fragment 269 */ 270 private String getRealSpec( URL url, String ref ) 271 { 272 if( null != ref ) 273 { 274 String spec = url.toString(); 275 int j = spec.indexOf( ref ); 276 if( j > 0 ) 277 { 278 String s = spec.substring( 0, j ); 279 String version = url.getUserInfo(); 280 if( null != version ) 281 { 282 s = s + "#" + version; 283 } 284 return s; 285 } 286 } 287 return url.toString(); 288 } 289 }